package com.strawcom.charmring.view;

import java.util.ArrayList;
import java.util.List;

import org.litepal.crud.DataSupport;

import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Shader.TileMode;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.strawcom.charmring.App;
import com.strawcom.charmring.C;
import com.strawcom.charmring.R;
import com.strawcom.charmring.bean.DailySummary;
import com.strawcom.charmring.util.FormatUtil;

/**
 * display data information after exercise
 * 
 * @author WangPeng
 */
public class ChartView_back extends View {
	public static class ExerciseInfo {
		public String day1;
		public String day2;
		public float weight;
		public float energy;

		public ExerciseInfo() {
		}

		public ExerciseInfo(String day1, String day2, float weight, float energy) {
			this.day1 = String.valueOf(day1);
			this.day2 = day2;
			this.weight = Math.round(weight * 10) / 10f;
			this.energy = Math.round(energy * 10) / 10f;
		}
	}

	private final List<ExerciseInfo> infoList = new ArrayList<ExerciseInfo>();
	private final int COUNT = 7;
	private final Paint mPaint = new Paint();
	private final Path mPath = new Path();
	private Typeface typeface;
	private LinearGradient linearGradientBackground, linearGradientLight;
	private DashPathEffect dashPathEffect;

	private int mWidth;
	private int mHeight;
	private float padding;
	private float titleHeight;
	private float squareHeight;
	private float squareCellWidth;
	private float energyCellHeight, weightCellHeight;
	private float tipTextSize, titleTextSize, valueTextSize, unitTextSize;
	private float energyWidth;
	private float weightWidth;
	private float pointRadius;
	private Bitmap bmpLight;
	private float lightLeft;
	private float lightWidth;

	private float percent;
	private final int PRESSED_NONE = 0;
	private final int PRESSED_ENERGY = 1;
	private final int PRESSED_WEIGHT = 2;
	private int pressed = PRESSED_NONE;
	private float anim;

	private String[] titles, units;

	public ChartView_back(Context context) {
		this(context, null);
	}

	public ChartView_back(Context context, AttributeSet attrs) {
		super(context, attrs);
		setLayerType(LAYER_TYPE_SOFTWARE, null);
		typeface = App.i().tfYouYuan;
		titles = getResources().getStringArray(R.array.exercise_summary_week_info);
		units = getResources().getStringArray(R.array.exercise_summary_week_unit);
	}

	// test 这种方法不稳定 ，应该使用日历类
	public static ExerciseInfo convertDailySummaryToExerciseInfo(DailySummary dailySummary) {
		ExerciseInfo exerciseInfo = new ExerciseInfo();
		exerciseInfo.day1 = FormatUtil.formatDate(dailySummary.getDate(), C.exercise.record_date_pattern, FormatUtil.dd);
		String E = FormatUtil.formatDate(dailySummary.getDate(), C.exercise.record_date_pattern, FormatUtil.E);
		final String[] weeks = new String[] { "\u65e5", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", };
		for (String w : weeks) {
			if (E.contains(w)) {
				E = w;
				break;
			}
		}
		exerciseInfo.day2 = E;
		exerciseInfo.weight = dailySummary.getWeight();
		exerciseInfo.energy = dailySummary.queryExerciseEnergy();
		return exerciseInfo;
	}

	public void setValueInfo(List<DailySummary> dailySummaryInfoList) {
		if (dailySummaryInfoList == null || dailySummaryInfoList.size() < 1) {
			throw new IllegalArgumentException("ChartView setValueInfo() empty params");
		} else if (dailySummaryInfoList.size() % 7 != 0) {
			throw new IllegalArgumentException("ChartView setValueInfo() params count % 7 != 0");
		}

		infoList.clear();
		for (DailySummary dailySummary : dailySummaryInfoList) {
			infoList.add(convertDailySummaryToExerciseInfo(dailySummary));
		}
		
		postInvalidate();
	}

	@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		mWidth = w;
		mHeight = h;
		padding = mWidth * 0.01f;
		tipTextSize = mWidth * 0.045f;
		titleTextSize = mWidth * 0.08f;
		valueTextSize = mWidth * 0.22f;
		unitTextSize = mWidth * 0.08f;
		titleHeight = mHeight * 0.3f;
		squareHeight = mHeight - tipTextSize - padding * 16;
		weightWidth = mWidth * 0.005f;
		energyWidth = weightWidth * 3.5f;
		pointRadius = mWidth * 0.022f;
		squareCellWidth = (mWidth - padding * 6) / 7;
		final float ene = calcMaxValueInEnergy();
		energyCellHeight = ene == 0 ? 0 : ((squareHeight - titleHeight) / ene) * 0.8f;
		final float wei = calcMaxValueInWeight();
		weightCellHeight = wei == 0 ? 0 : ((squareHeight - titleHeight) / wei) * 0.5f;

		lightLeft = squareCellWidth / 2 - pointRadius;
		lightWidth = mWidth - squareCellWidth + 2 * pointRadius - squareCellWidth / 2;

		linearGradientBackground = new LinearGradient(0, titleHeight, 0, mHeight, new int[] { 0x00ffffff, 0x44ffffff, 0x99ffffff },
				new float[] { 0f, 0.75f, 1f }, TileMode.REPEAT);
		dashPathEffect = new DashPathEffect(new float[] { padding, padding }, 0);
		linearGradientLight = new LinearGradient(0, 0, 0, (squareHeight - titleHeight + pointRadius), new int[] { 0x00ffffff, 0x99ffffff,
				0xffffffff }, new float[] { 0f, 0.6f, 1f }, TileMode.REPEAT);
		bmpLight = Bitmap.createBitmap((int) (squareCellWidth / 2), (int) (squareHeight - titleHeight + pointRadius), Config.ARGB_8888);
		Canvas canvas = new Canvas(bmpLight);
		mPaint.setShader(linearGradientLight);
		canvas.drawRect(0, 0, bmpLight.getWidth(), bmpLight.getHeight(), mPaint);
		mPaint.setShader(null);
	}

	@Override protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// draw background
		mPaint.setShader(linearGradientBackground);
		for (int i = 0; i < COUNT; i++) {
			final float left = (squareCellWidth + padding) * i;
			final float right = left + squareCellWidth;
			canvas.drawRect(left, titleHeight, right, mHeight, mPaint);
		}
		mPaint.reset();
		mPaint.setAntiAlias(true);
		mPaint.setTypeface(typeface);
		mPaint.setColor(0xffadadad);
		mPaint.setTextSize(tipTextSize);
		for (int i = 0; i < infoList.size(); i++) {
			final float left = (squareCellWidth + padding) * i;
			canvas.drawText(infoList.get(i).day1, left + (squareCellWidth - calcTextOffset(infoList.get(i).day1, mPaint)) / 2, squareHeight
					+ padding * 10, mPaint);
			canvas.drawText(infoList.get(i).day2, left + (squareCellWidth - calcTextOffset(infoList.get(i).day2, mPaint)) / 2, mHeight
					- padding * 3, mPaint);
		}
		// dynamic by animation
		if (anim > 0) {
			anim = anim - 0.1f;
		}
		// draw line
		mPaint.setStyle(Style.STROKE);
		if (anim > 0 && pressed == PRESSED_ENERGY) {
			mPaint.setARGB(90 + (int) (165 * anim), 255, 255, 255);
		}
		else {
			mPaint.setARGB(pressed == PRESSED_ENERGY ? 90 : 255, 255, 255, 255);
		}
		mPaint.setStrokeWidth(weightWidth);
		mPaint.setPathEffect(dashPathEffect);
		mPath.reset();
		mPath.moveTo(squareCellWidth / 2, squareHeight - infoList.get(0).weight * weightCellHeight);
		for (int i = 1; i < infoList.size(); i++) {
			mPath.lineTo(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).weight * weightCellHeight);
		}
		canvas.drawPath(mPath, mPaint);
		mPaint.setStrokeWidth(energyWidth);
		mPaint.setPathEffect(null);
		if (anim > 0 && pressed == PRESSED_WEIGHT) {
			mPaint.setARGB(90 + (int) (165 * (anim)), 255, 255, 255);
		}
		else {
			mPaint.setARGB(pressed == PRESSED_WEIGHT ? 90 : 255, 255, 255, 255);
		}
		mPath.reset();
		mPath.moveTo(squareCellWidth / 2, squareHeight - infoList.get(0).energy * energyCellHeight);
		for (int i = 1; i < infoList.size(); i++) {
			mPath.cubicTo(squareCellWidth * 0.8f + (i - 1) * (squareCellWidth + padding), squareHeight - infoList.get(i - 1).energy
					* energyCellHeight, squareCellWidth * 0.2f + i * (squareCellWidth + padding), squareHeight - infoList.get(i).energy
					* energyCellHeight, squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).energy
					* energyCellHeight);
		}
		canvas.drawPath(mPath, mPaint);
		// draw point
		mPaint.setStyle(Style.FILL);
		if (anim > 0) {
			if (pressed == PRESSED_ENERGY) {
				mPaint.setARGB(255, 255, 255 - (int) (127 * anim), (int) (255 * (1 - anim)));
				for (int i = 0; i < infoList.size(); i++) {
					canvas.drawCircle(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).energy
							* energyCellHeight, pointRadius, mPaint);
				}
				mPaint.setARGB((int) (255 * anim), 255, 128, 0);
				for (int i = 0; i < infoList.size(); i++) {
					canvas.drawCircle(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).weight
							* weightCellHeight, pointRadius, mPaint);
				}
			}
			else if (pressed == PRESSED_WEIGHT) {
				mPaint.setARGB((int) (255 * anim), 255, 128, 0);
				for (int i = 0; i < infoList.size(); i++) {
					canvas.drawCircle(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).energy
							* energyCellHeight, pointRadius, mPaint);
				}
				mPaint.setARGB(255, 255, 255 - (int) (127 * anim), (int) (255 * (1 - anim)));
				for (int i = 0; i < infoList.size(); i++) {
					canvas.drawCircle(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).weight
							* weightCellHeight, pointRadius, mPaint);
				}
			}
		}
		else {
			if (pressed == PRESSED_NONE) {
				mPaint.setARGB(255, 255, 128, 0);
				for (int i = 0; i < infoList.size(); i++) {
					canvas.drawCircle(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).energy
							* energyCellHeight, pointRadius, mPaint);
					canvas.drawCircle(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).weight
							* weightCellHeight, pointRadius, mPaint);
				}
			}
			else if (pressed == PRESSED_ENERGY) {
				for (int i = 0; i < infoList.size(); i++) {
					mPaint.setARGB(255, 255, 255, 255);
					canvas.drawCircle(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).energy
							* energyCellHeight, pointRadius, mPaint);

				}
			}
			else if (pressed == PRESSED_WEIGHT) {
				mPaint.setARGB(255, 255, 255, 255);
				for (int i = 0; i < infoList.size(); i++) {
					canvas.drawCircle(squareCellWidth / 2 + i * (squareCellWidth + padding), squareHeight - infoList.get(i).weight
							* weightCellHeight, pointRadius, mPaint);
				}
			}
		}
		// draw info
		if (anim > 0) {
			mPaint.setARGB((int) (170 * (1 - anim)), 255, 255, 255);
		}
		else {
			mPaint.setARGB(pressed != PRESSED_NONE ? 170 : 0, 255, 255, 255);
		}
		final String value = String.valueOf(getValue());
		mPaint.setTextSize(titleTextSize);
		canvas.drawText(getTitle(), padding * 3, titleTextSize / 2 + titleTextSize * (1 - anim), mPaint);
		mPaint.setTextSize(valueTextSize);
		final float valueWidth = calcTextOffset(value, mPaint);
		mPaint.setTextSize(unitTextSize);
		final float unitWidth = calcTextOffset(getUnit(), mPaint);
		mPaint.setTextSize(valueTextSize);
		canvas.drawText(value, (mWidth - valueWidth - unitWidth) / 2, titleHeight - padding * 5, mPaint);
		mPaint.setTextSize(unitTextSize);
		canvas.drawText(getUnit(), (mWidth + valueWidth - unitWidth) / 2, titleHeight - padding * 5, mPaint);
		// draw pressed
		if (pressed != PRESSED_NONE) {
			canvas.drawBitmap(bmpLight, lightLeft + percent * lightWidth, titleHeight, mPaint);
		}

		mPaint.reset();
		if (anim > 0) {
			invalidate();
		}
	}
	
	private float calcMaxValueInEnergy() {
		Cursor cursor = DataSupport.findBySQL("select max(sum_energy) as max_sum_energy from (select sum(calorie) as sum_energy from Calories group by dailySummary_id)");
		cursor.moveToFirst();
		float maxSumEnergy = cursor.getFloat(cursor.getColumnIndex("max_sum_energy"));
		cursor.close();
		return maxSumEnergy;
	}
	
	private float calcMaxValueInWeight() {
		Cursor cursor = DataSupport.findBySQL("select max(weight) as max_weight from DailySummary");
		cursor.moveToFirst();
		float maxWeight = cursor.getFloat(cursor.getColumnIndex("max_weight"));
		cursor.close();
		return maxWeight;
	}

	private float calcTextOffset(String text, Paint paint) {
		float[] textWidths = new float[text.length()];
		paint.getTextWidths(text, textWidths);
		float textTotalWidth = 0;
		for (float f : textWidths) {
			textTotalWidth += f;
		}
		return textTotalWidth;
	}

	@Override public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			percent = event.getX() / mWidth;
			float downY = event.getY();
			if (downY > titleHeight && downY < mHeight - (mHeight - titleHeight) / 2) {
				pressed = PRESSED_ENERGY;
				anim = 1;
				invalidate();
			}
			else if (downY > mHeight - (mHeight - titleHeight) / 2) {
				pressed = PRESSED_WEIGHT;
				anim = 1;
				invalidate();
			}
			return PRESSED_NONE != pressed;
		case MotionEvent.ACTION_MOVE:
			percent = event.getX() / mWidth;
			invalidate();
			break;
		case MotionEvent.ACTION_UP:
			pressed = PRESSED_NONE;
			anim = 0;
			invalidate();
			break;
		}
		return super.onTouchEvent(event);
	}

	private float getValue() {
		int result = Math.round(percent * (COUNT - 1));
		if (pressed == PRESSED_ENERGY) {
			return infoList.get(result).energy;
		}
		else if (pressed == PRESSED_WEIGHT) {
			return infoList.get(result).weight;
		}
		return 0;
	}

	private String getTitle() {
		if (pressed == PRESSED_ENERGY) {
			return titles[0];
		}
		else if (pressed == PRESSED_WEIGHT) {
			return titles[1];
		}
		return "";
	}

	private String getUnit() {
		if (pressed == PRESSED_ENERGY) {
			return units[0];
		}
		else if (pressed == PRESSED_WEIGHT) {
			return units[1];
		}
		return "";
	}
}
